package cn.shadow.service;

import cn.shadow.concurrent.DisruptorExecutor;
import com.sun.istack.internal.NotNull;
import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.Closeable;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@Data
public class ThreadService implements IThreadService, Closeable {
    private final Set<Thread> gameExecSet;
    /**
     * 数据库线程
     */
    private final ExecutorService dbExec;
    final int GAME_THREAD_COUNT_TO_MOD;
    private final ExecutorService fastDbExec;
    /**
     * 用户线程池
     */
    private final DisruptorExecutor[] gameExc;

    /**
     * 定时任务
     */
    private final ScheduledThreadPoolExecutor scheduledExec;

    public ThreadService() {
        int dbThreadCount = Runtime.getRuntime().availableProcessors()-1; //cpu核数的两倍
        gameExc = new DisruptorExecutor[dbThreadCount];
        this.gameExecSet = new HashSet<>(dbThreadCount);
        GAME_THREAD_COUNT_TO_MOD = dbThreadCount - 1;
        for (int i = 0; i < dbThreadCount; i++) {
            gameExc[i] = new DisruptorExecutor(i, 8192, "用户线程_" + i);
            this.gameExecSet.add(gameExc[i].getThread());
        }

        this.dbExec = new ThreadPoolExecutor(dbThreadCount, dbThreadCount, 60L, TimeUnit.SECONDS,
                new LinkedTransferQueue<>(),
                new MyThreadFactory("数据库线程_", Thread.NORM_PRIORITY));

        this.fastDbExec = new ThreadPoolExecutor(dbThreadCount, dbThreadCount, 60L, TimeUnit.SECONDS,
                new LinkedTransferQueue<>(),
                new MyThreadFactory("数据库快速线程_", Thread.MAX_PRIORITY));

        scheduledExec = new ScheduledThreadPoolExecutor(dbThreadCount,
                new MyThreadFactory("定时更新线程_", Thread.MAX_PRIORITY));

    }

    @Override
    public ExecutorService getDbExecutor() {
        return dbExec;
    }

    @Override
    public ExecutorService getFastDbExecutor() {
        return fastDbExec;
    }

    @Override
    public ScheduledExecutorService getScheduledExecutorService() {
        return scheduledExec;
    }

    @Override
    public void close() {
        // 关闭顺序必须是schedule, gameExec, dbExec
        // schedule可能会放任务到gameExec
        // gameExec可能会放任务到dbExec
        shutDownUpdateExec();
        shutDownGameExec();
        shutDownDbExec();
    }

    private void shutDownDbExec() {
        dbExec.shutdown();
    }

    private void shutDownGameExec() {
        for (DisruptorExecutor service : gameExc) {
            service.shutdown();
        }
    }

    public DisruptorExecutor getExecutor(int id) {
        return gameExc[id & GAME_THREAD_COUNT_TO_MOD];
    }

    private void shutDownUpdateExec() {
        scheduledExec.shutdown();
    }


    /**
     * 线程工厂
     */
    private static class MyThreadFactory implements ThreadFactory {
        private final String threadName;
        private final AtomicInteger idCounter;
        private final int priority;

        public MyThreadFactory(String threadName, int priority) {
            this.threadName = threadName;
            this.idCounter = new AtomicInteger();
            this.priority = priority;
        }

        @Override
        public Thread newThread( Runnable task) {
            Thread result =
                    new Thread(task, threadName + idCounter.incrementAndGet());
            result.setPriority(priority);
            return result;
        }
    }
}
